
#include <BFont>
#include "member_BTreeItem.h"
#include "member_BTreeWidget.h"
#include "member_BObject.h"

using namespace BWE;

member_BTreeWidget::member_BTreeWidget(BTreeWidget* treeWidget)
{
	boss = treeWidget;
	indent = -1;
	selectMode = Select_Multiple | Select_Continuous;
	arrowAlign = Align_Center;
	arrowVisible = true;
	dirty = true;
	dirtyVisual = true;
	pressed = false;
	hoveredArrow = false;
	hoveredItem = 0;
	itemSize.set(-1, -1);
	itemAlign = Align_None;
	itemPolicy = Policy_Growing;
	itemSpacing = 1;
}
member_BTreeWidget::~member_BTreeWidget()
{

}

void member_BTreeWidget::dirtyItem(BTreeItem* item)
{
	item_member(item)->dirty = true;
	item_member(item)->dirtyStyle = true;
	BArray<BTreeItemHolder>& children = item_member(item)->children;
	for (int i = 0; i < children.size(); i++)
	{
		BTreeItem* child = children[i];
		dirtyItem(child);
	}
}

void member_BTreeWidget::freshWidget(BTreeItem* item, bool visual)
{
	if (visual && !item_member(item)->visible)
		visual = false;
	if (item_member(item)->widget)
		item_member(item)->widget->setVisible(visual);
	if (visual && !item_member(item)->expanded)
		visual = false;
	for (int i = 0; i < item_member(item)->children.size(); i++)
	{
		BTreeItem* child = item_member(item)->children[i];
		freshWidget(child, visual);
	}
}

bool member_BTreeWidget::freshArea()
{
	const BStyle* style = boss->realStyle();
	const BFont* font = boss->realFont();
	int rowHeight = font->size();

	realArrowSize.reset();
	realSpacing = 0;
	if (arrowVisible)
	{
		realSpacing = itemSpacing;
		realArrowSize = arrowSize;
		if (realArrowSize.width() < 1)
			realArrowSize.width() = rowHeight / 2;
		if (realArrowSize.height() < 1)
			realArrowSize.height() = rowHeight / 2;
	}

	realIndent = indent;
	if (realIndent < 0)
		realIndent = rowHeight * (-indent);

	int x = 0;
	int y = 0;
	BSize areaSize;
	for (int i = 0; i < items.size(); i++)
	{
		BTreeItem* item = items[i];
		freshItemRect(style, font, item, x, y, areaSize);
	}
	BRect area = boss->area();
	area.setSize(areaSize);
	boss->setArea(area);

	return true;
}
void member_BTreeWidget::freshItemRect(const BStyle* style, const BFont* font, BTreeItem* item, int x, int& y, BSize& areaSize)
{
	if (!item_member(item)->visible)
		return;

	if (item_member(item)->dirtyStyle)
	{
		item_member(item)->dispenseStyles(style);
		item_member(item)->applyStyle(style);
		item_member(item)->dirtyStyle = false;
		item_member(item)->dirty = true;
	}
	if (item_member(item)->dirty)
	{
		item_member(item)->freshSize(font, 0);
		item_member(item)->indent = item->level() * realIndent;
		item_member(item)->dirty = false;
	}

	BSize realSize = item_member(item)->hintSize;
	if (realSize.height() < realArrowSize.height())
		realSize.height() = realArrowSize.height();

	if (itemSize.width() > 0 && realSize.width() < itemSize.width())
		realSize.width() = itemSize.width();
	if (itemSize.height() > 0 && realSize.height() < itemSize.height())
		realSize.height() = itemSize.height();

	int arrowAreaWidth = realArrowSize.width();
	int arrowAreaHeight = realArrowSize.height();
	if (arrowVisible)
	{
		if (arrowAreaWidth < font->size())
			arrowAreaWidth = font->size();
		if (arrowAreaHeight < font->size())
			arrowAreaHeight = font->size();
	}

	item_member(item)->arrowArea.setSize(arrowAreaWidth, arrowAreaHeight);
	item_member(item)->setPos(x + item_member(item)->indent + arrowAreaWidth + realSpacing, y);
	item_member(item)->setSize(realSize);
	item_member(item)->area.reset(x, y);
	item_member(item)->area.expand(item_member(item)->rect());

	y = item_member(item)->area.bottom() + itemSpacing;
	areaSize.height() = item_member(item)->area.bottom() + itemSpacing;
	if (areaSize.width() < item_member(item)->area.width())
		areaSize.width() = item_member(item)->area.width();

	if (item_member(item)->expanded)
	{
		for (int i = 0; i < item->childCount(); i++)
		{
			BTreeItem* child = item->child(i);
			freshItemRect(style, font, child, x, y, areaSize);
			item_member(item)->area.expand(item_member(child)->area);
		}
	}
}
void member_BTreeWidget::freshVisualItems()
{
	visualItems.reset();
	const BRect& area = boss->area();
	const BRect& crect = boss->centerRect();
	BSize areaSize = boss->areaSize();
	for (int i = 0; i < items.size(); i++)
	{
		BTreeItem* item = items[i];
		if (!item_member(item)->visible)
			continue;
		adjustVisualItem(item, area.pos(), crect, areaSize);
	}
}
void member_BTreeWidget::adjustVisualItem(BTreeItem* item, const BPoint& offset, const BRect& crect, const BSize& areaSize)
{
	BRect area = item_member(item)->area + offset;
	if (area.bottom() >= crect.top() && area.top() <= crect.bottom())
	{
		if (itemPolicy & Policy_Expanding)
		{
			item_member(item)->area.setWidth(areaSize.width());
			int width = areaSize.width() - item_member(item)->pos.x();
			item_member(item)->setWidth(width);
			item_member(item)->adjustArrowRect(offset);
			if (BWidget* widget = item_member(item)->widget)
			{
				BPoint absPos = item_member(item)->pos + offset;
				widget->setRect(item_member(item)->ia_iconRect + absPos);
			}
		}
		visualItems.append(item);
		if (item_member(item)->expanded)
		{
			for (int i = 0; i < item->childCount(); i++)
			{
				BTreeItem* child = item->child(i);
				if (!item_member(child)->visible)
					continue;
				adjustVisualItem(child, offset, crect, areaSize);
			}
		}
	}
}
bool member_BTreeWidget::collectPrevItems(BTreeItem* item, BTreeItem* lastItem, BTreeItemArray& collectedItems)
{
	while (item)
	{
		collectedItems.append(item);
		if (item == lastItem)
			return true;
		if (item->expanded())
		{
			for (int i = 0; i < item->childCount(); i++)
			{
				BTreeItem* child = item->child(i);
				if (collectPrevItems(child, lastItem, collectedItems))
					return true;
			}
		}
		item = item->prev();
	}
	return false;
}
bool member_BTreeWidget::collectNextItems(BTreeItem* item, BTreeItem* lastItem, BTreeItemArray& collectedItems)
{
	while (item)
	{
		collectedItems.append(item);
		if (item == lastItem)
			return true;
		if (item->expanded())
		{
			for (int i = 0; i < item->childCount(); i++)
			{
				BTreeItem* child = item->child(i);
				if (collectNextItems(child, lastItem, collectedItems))
					return true;
			}
		}
		item = item->next();
	}
	return false;
}

void member_BTreeWidget::expandAll(BTreeItem* item)
{
	if (item)
	{
		if (!item_member(item)->expanded)
		{
			item_member(item)->expanded = false;
			boss->emit(Signal_ItemExpanded, item);
		}
		for (int i = 0; i < item->childCount(); i++)
		{
			BTreeItem* child = item->child(i);
			expandAll(child);
		}
	}
}
void member_BTreeWidget::shrinkAll(BTreeItem* item)
{
	if (item)
	{
		if (item_member(item)->expanded)
		{
			item_member(item)->expanded = false;
			boss->emit(Signal_ItemShrinked, item);
		}
		for (int i = 0; i < item->childCount(); i++)
		{
			BTreeItem* child = item->child(i);
			shrinkAll(child);
		}
	}
}
